﻿//***********************************************************************
// Assembly         : phpmk
// Author           : sy
// Created          : 06-14-2010
//
// Last Modified By : sy
// Last Modified On : 06-15-2010
// Description      : 
//
// Copyright        : (c) Another-D-Mention Software. All rights reserved.
//***********************************************************************
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using phpmk.ADM.Out;
using phpmk.ADM.Core;
using System.Xml;
using System.IO;
using phpmk.ADM.Core.Model;
using System.Reflection;
using phpmk.ADM.Core.Configuration;

namespace phpmk.ADM.Commands.Create
{
    class CreateCommand : ICommand 
    {
        private StringDictionary arguments;
        private bool AddComments;
        private string ProjectName;
        private XmlDocument xmlDoc;
        private DataModel Model;

        public void Execute(StringDictionary args) {
            Output.GetInstance().Write("Creating configuration file...\n", true);

            this.arguments = args;
            
            this.AddComments = (this.arguments.ContainsKey("comments"));
            this.ProjectName = this.arguments.ContainsKey("name") ? this.arguments["name"] : Constants.DefaultProjectName;
            
            if (ConfigFile.GetInstance().Loaded && !this.arguments.ContainsKey("override")) {
                Output.GetInstance().Warning("There already is a configuration file! Overriding it will destroy your current settings");
                while (true) {
                    Console.Write("\nAre you sure you want to override it [Y/N] : ");
                    ConsoleKeyInfo Result = Console.ReadKey(false);
                    if (Result.KeyChar == 'N' || Result.KeyChar == 'n') {
                        Output.GetInstance().SetStatus(ActionStatus.ABBORT);
                        return;
                    } else if (Result.KeyChar == 'Y' || Result.KeyChar == 'y') {
                        break;
                    }
                    Console.CursorTop -= 1;
                }
            }

            xmlDoc = new XmlDocument();
            XmlDeclaration xmlDec = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
            XmlElement root = xmlDoc.CreateElement("project");

            Model = new DataModel();
            SerializeObject(Model, root);

            xmlDoc.InsertBefore(xmlDec, xmlDoc.DocumentElement);
            xmlDoc.AppendChild(root);

            try {
                xmlDoc.Save(Directory.GetCurrentDirectory() + "\\" + Constants.ConfigFile);
            } catch (Exception ex) {
                Output.GetInstance().SetStatus(ActionStatus.FAILED);
                Output.GetInstance().Write("");
                Output.GetInstance().Error(ex.Message);
                return;
            }
            Output.GetInstance().SetStatus(ActionStatus.OK);
        }

        private void SerializeObject(Object Obj, XmlNode parentnode)
        {
            Configurable Attr;
            XmlNode node;
            foreach (FieldInfo Field in Obj.GetType().GetFields()) {
                foreach (Attribute attr in Field.GetCustomAttributes(false)) {
                    Attr = attr as Configurable;
                    if (null != Attr) {
                        if (Attr.IsAttribute) {
                            AddAttribute(parentnode, Field.Name.Substring(0, 1).ToLower() + Field.Name.Substring(1), Attr.DefaultValue);
                            continue;
                        }
                        node = CreateElement(parentnode, Field.Name.Substring(0, 1).ToLower() + Field.Name.Substring(1), Attr.Comment, Attr.DefaultValue);
                        if (Field.FieldType.Name != "String") {
                            if (Field.FieldType.IsSubclassOf(typeof(Array))) {
                                SerializeObject((Field.GetValue(Obj) as Array).GetValue(0), node);
                            } else {
                                SerializeObject(Field.GetValue(Obj), node);
                            }
                        }
                    }
                }
            }
        }

        private void AddAttribute(XmlNode parent, string name, string value)
        {
            XmlAttribute atribute = xmlDoc.CreateAttribute(name);
            atribute.InnerText = value;
            parent.Attributes.Append(atribute);
        }

        private XmlNode CreateElement(XmlNode parent, string name, string comment, object value)
        {
            if (name == "name") value = ProjectName;

            if (!String.IsNullOrEmpty(comment)) {
                if (AddComments) {                    
                    if (comment.IndexOf('\n') != -1) {
                        string[] comments = comment.Split('\n');
                        foreach(string com in comments) {
                            CreateComment(parent, com);
                        }
                    } else {
                        CreateComment(parent, comment);
                    }
                }
            }
            XmlNode xmlTag = xmlDoc.CreateNode(XmlNodeType.Element, name, null);
            if (value != null) {
               xmlTag.InnerText = (string)value;
            }
            parent.AppendChild(xmlTag);
            return xmlTag;
        }

        private void CreateComment(XmlNode parent, string comment)
        {
            XmlNode commentTag = xmlDoc.CreateNode(XmlNodeType.Comment, "", null);
            commentTag.InnerText = comment;
            parent.AppendChild(commentTag);
        }

        public void Help()
        {
            Output output = Output.GetInstance();
            output.Info("Creates a new " + Constants.ConfigFile + " configuration file in the current folder. You must edit and validate (using the -validate command) the configuration file before building/deploying");
            output.Write("\nUsage Info: phpmk -create [/parameter value ....]");
            output.Write("\nParameters:");
            output.StartTable(2);
            output.AddRow(new string[] {" /name \"my name\"", "Project name." });
            output.AddRow(new string[] {" /comments", "Adds comments to configuration tags. Default is False"});
            output.AddRow(new string[] {" /override", "Override any existing configuration file" });
            output.EndTable();
        }

        public string Info()
        {
            return "Creates a new project configuration in current folder";
        }
    }
}
